home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Technotools
/
Technotools (Chestnut CD-ROM)(1993).ISO
/
database
/
db3stock
/
db3stock.doc
< prev
next >
Wrap
Text File
|
1986-04-13
|
20KB
|
355 lines
As programmers, we all have several creative problem-solving routines we have
written for clients that we like to brag about -- they were clever, compact,
and tight. They might have even compiled and run perfectly the first time.
But let's face it -- writing meaningful, consistent user interfaces with
exceptional attention to thorough error-trapping takes a lot of TIME, perhaps
even the most time we spend in the actual coding development and code writing
process. It certainly increases the bulkiness of our code (by way of many
K-bytes of TEXT data structures).
But this aspect of programming -- user interface --is the singularly most
important determining factor of client satisfaction. As a maintenance
programmer, I have been apalled at the abject lack of user interfaces. In
one situation, the previous coder before me wrote coder before me wrote no
code to give the user any status messages indicating what was happening
when the user was finished working with data. i.e., "Saving the new data to
disk", "Deleting your record from the file", etc.). The little red light
on the drive may have come on, but what was happening was anyone's guess.
When an internal error from an error trap was encountered, there were often
no messages -- simply a return to the previous calling menu before the error.
Apparently, the user was supposed know what error had been committed. Even
worse, some of the important data input was not error-trapped that could
overwrite data in an unintended record, or simply crash the program.
In virtually EVERY maintenance program I have ever worked on, I have been
absolutely shocked at the AUSTERITY of the input screens I have seen. There
is no regard for the fact that clients have to look at that screen, perhaps
as often as long as eight full hours EVERY WORKING DAY. If the screen is
dull and unattractive, how long do you think it will be before they start
making mistakes--and then blaming YOU, the programmer, for data crashes???
The recently vast improving user interfaces in commercially available general-
user software (word processors, database managers, spreadsheets) makes
inexcusable this "let's-continue-the-awe-about-computers-and-programming-
with-mystery" fashion of doing business with a client. I predict in a few
years anyone thinking that nothing less than absolutely superior user
interfaces --including top-notch, attractive screens-- for a common end user
will render that individual unemployable in programming. And since dbaseIII
handles much of our file handling activities with single lines of code and/or
commands, there is now more time for programmers to spend more of their
precious time with good user interface development.
To that end, then, I have developed some simple, yet extremely useful
subroutines that can be used almost as meta-commands. It makes development
a lot simpler.
This DB3STOCK.ARC file contains the following files:
DB3STOCK.DOC -- this (introductory) file
bigboxdt.prg -- A simple "MAIN MENU" type, graphics-drawn box that centers,
highlights, and displays a header message at the top inside
line of the box, and then displays the date and time at the
left and right sides of the box, respectively.
boxclear.prg -- A routine that clears the inside of BIGBOXDT without having
to clear the screen and redraw it. This is helpful for
continuous LISTs or DISPLAYs of data. The starting line of
the clearing procedure is defined by the numeric variable
LN, and it is helpful to have it user defineable BEFORE ent-
ering the routine, as you may have subheaders towards the
top of the screen that you do NOT want to erase and redraw.
smallbox.prg -- A routine that creates a smaller box on the screen. Useful
for help screens or flagging important data entry.
slinboxm.prg -- A routine that draws a single line box in the middle of the
screen, and then centers, highlights and displays a user-
defined message (MSG) inside the box.
slinboxt.prg -- A routine that draws a single line box at the top of the
screen, and then centers, highlights and displays a user-
defined message (MSG) inside the box.
slinboxb.prg -- A routine that draws a single line box at the bottom of the
screen, and then centers, highlights and displays a user-
defined message (MSG) inside the box.
dlinboxm.prg -- These three programs are indentical to their "SLINBOXx" sub-
dlinboxt.prg -- routines above, with the exception that they use a double
dlinboxb.prg -- line graphic-oriented box instead of the single line box.
linprm23.prg -- This is a metacommand that will save no ends of programming,
particularly where multiple branches are about to occur. Let's
take an example: you have displayed a screen of data from a
file record. The decision list is as follows:
"<A>dd <E>dit <D>elete <N>ext <P>revious <X>Exit"
Merely define the variable "MSG" as the text in quotes above.
Define the variable "TEST" as the string literal :"AEDNPX" .
Define TZ as " ". Now the next line of code would be "DO
LINPRM23". The routine centers, highlights and displays the
text and waits for the <A>, <E>, <D>, <N>, <P>, or <X> key
to be pressed. The input is automatically made uppercase.
And only those individual keys from "TEST" are acceptable
input. The final code in this example would look like this:
tz=" "
test="AEDNPX"
msg="<A>dd <E>dit <D>elete <N>ext <P>revious <X>Exit"
do linprm23
You are now free to use the appropriate IF/ENDIF or
DO CASE/CASE statements -- based on the key pressed.
linmsg23.prg -- Sometimes you will want to put a message on the screen and
wait for the user to acknowledge the message. That is exactly
what this routine does. You define the message, and it
centers, highlights, and displays the message, and then waits
for any keystroke. As in the subroutine above, you define the
"MSG" and "TZ" variables before entering the routine. This
routine is FAR more attractive than the WAIT statement, and
is more helpful to an end user because you can customize the
message to help guide the user when he continues.
prtmsg23.prg -- This routine is identical to the routine above, except that
no input of any kind by the user is required. It merely high-
lights, centers, and displays the message ("MSG") at the bottom
of the screen. This routine is immensely useful for writing
those oh-so-needed messages like, "Saving new data to disk"
or "ACCOUNTS CLOSING IN PROGRESS. Please wait." You can
INCLUDE MACRO variables as part of the message for further
convenience, such as :
msg="Department "+&deptID+" has "+str(records,4,0)+" entries."
DO PRTMSG23
getfld23.prg -- This is one of my favorite routines. If I want a user to input
data that is not part of the input screen nor part of the data
file (say, it is part of an overall calculation or series of
calculations), and I DON'T WANT TO LOSE ANY OF THE SCREEN DATA
DISPLAYED, I can avoid drafting the code that redraws the
screen and data by getting the information at the bottom of
the screen. It is attractive, gets the immediate and proper
attention of the user, and allows the coder to focus on getting
data! An example:
Mcost=0.00 : * the target data variable for user input.
FEELD=space(6) : * the length of the variable, pict "9999.99"
kol=0
msg="ENTER the total cost of the Advertisement :"
do getfld23
do while Mcost<=0 .or. Mcost>7290.05
Mcost=0
@ 23,kol get Mcost picture "9999.99" : * length=6 spaces
enddo
prevmo.prg -- A routine that calculates what the actual previous calendar
month is, REGARDLESS of what the current system date is.
nextmo.prg -- A routine that calculates what the actual NEXT calendar month
is, regardless of what the current system date is.
passwerd.prg -- A fully functional password program. It is misspelled on pur-
pose. Many public domain and commercially available dbase rou-
tines use "PASSWORD.PRG" as its namesake. I don't want to
accidentally overwrite any files you may have by that name when
you copy this file! You must first create a file from
within dbase III, called "SECURITY.DBF". It consists of one
field, of character, and 12 characters in length. The field
name should be called "ENTEROK". Then create a temporary
".PRG" file which contains ONLY the block of code from within
"PASSWERD.PRG" that starts from the comment: "PASSWORD ADDITION
ROUTINE starts here" to the comment: "PASSWORD ADDITION ROUTINE
ends here". Run that as a separate program and the first
record in the file will be the MASTER PASSWORD. ONLY the
MASTER PASSWORD will allow other passwords to be logged into
the SECURITY file. Just for fun, do a DISPLAY ALL of the
SECURITY.dbf file records from the dbase III interpreter.
lincount.prg -- is a routine that will keep a running count of all information
written to the screen or to the printer, and how many lines you
have left before the screen must be refreshed (BOXCLEAR), or
a page EJECT invoked. It also allows 6 headers to be used as
part of the top of your page, whether you are using to screen
or printer.
displrut.prg -- is a text file only. SEE DB3STOCK.TXT below.
You will notice that some of these routines require that several variables
need to be initialized BEFORE entering the routine. First, you might ask, "Why
not use the dbaseIII convention, DO <subroutine> WITH <parameters>?" Secondly,
you might ask, "What if my application is currently using the same named
variables as the routines above?"
In answer to the first question,
I avoid DO WITH constructs because you have to use a TWO SETS of variables to
successfully complete a DO WITH procedure -- one set to pass variables TO
the routine, and one set to RECEIVE the passed variables. You could use the
same variables as parameters, but dbase III has a myriad of memory variable
handling functions (RESTORE from <filename>.MEM [ADDITIVE], CLEAR [ALL | LIKE
<skeleton>, PUBLIC,PRIVATE,HIDDEN) that can, in conjunction with each other,
often create memory management conflicts, even amongst the most organized of
us. The dbase III Advanced Programmer's Guide (Castro, et. al.) strongly
advises against identical variable/parameter passing. Translation: it's
probably going to have bugs if you do. I always initialize variable(s) before
entering routines because : (1) it is ALWAYS easier to write (2) you have
fewer variable names in the long run to trace/debug for any given routine(s),
and (3) - whether the variables are PUBLIC or PRIVATE, initializing them
BEFORE invoking the routine makes them accessible to that called routine.
Frankly, I've hated PUBLIC/PRIVATE nonsense. Initializing variables just
before use is almost a sure way of emulating a "globalness" of your variable
condition -- something I always enjoyed about dbase II and BASIC.
In answer to the second question, I find that most applications programmers
have a unique style to their memory variable name assignments. In all the
maintenance program work I have done, I have not yet found ANY of my variable
names in my routines to be in conflict with the assignments of the code I had
to maintain. It might just be luck, but I rather doubt it. If you do have
problems with variable names, you will have to rename yours or rename mine.
As a matter of PRAGMATISM, (not ego), you might find it more time saving to
rename YOURS, for two reasons: (1) You know where all the locations of
your variables are, what they do, what they stand for, and what effect they
have on every aspect of all the other modules in your application. It's your
own code, so who else but you would know what affect variable naming
procedures and initialization assignments would do to those modules?
(2) Many of the subroutines above CALL EACH OTHER, "PASSWERD.PRG" in
particular. You know the domino theory. And it certainly applies to
variables in programming -- one module SNAFU's, and they probably all will
have a large or small SNAFU in them somewhere.
A final word about these routines. They take great care in forecasting the
environment that needs to exist after they have been executed. For example,
the routines that contain "??????23.PRG" initialize the set color commands,
clear from line 23 any existing "MSG", and print the new one. Where key
input is required, line 23 is CLEARED, so you don't have to remember to code
that yourself. Where it is not required, of course, the "MSG" remains on
screen, as the routine assumes the condition exhibited by the message remains
in effect until another message (or screen!) indicates otherwise.
DB3STOCK.OBJ -- an 8088-relocatable object code file, which can be linked
with PLINK86, in the formation of final dbaseIII compiled
".EXE" programs. It is a Clipper (TM) compiled file of all
the source programs (subroutines) above. If you write in
dbaseIII and compile your applications using the Clipper
compiler, you do not need to recompile these programs. Merely
include this file as the LAST object code file to link with
your other object code files, and they will be available to
your applications program. The only stipulation is, of
course, that when compiling your other programs that make up
the total of your application is that you do NOT use the
convention,
"clipper <filename>"
where <filename> is the main calling program that calls all
other programs. Rather, use the convention:
"clipper @<filelist>.CLP"
where <filelist>.CLP is an ascii text file listing of ALL the
programs you need compiled for your application. Don't forget,
in using this latter convention, the first filename in the
<filelist> should be <filename>, i.e., the main calling
program that calls all other programs. DO NOT list any of
the subroutines above in your <filelist>, as the DB3STOCK.OBJ
file already contains them.
DB3STOCK.TXT -- An ascii text file, which contains the following subroutines:
bigboxdt.prg
boxclear.prg
smallbox.prg
lineboxm.prg
slinboxm.prg
slinboxt.prg
slinboxb.prg
dlinboxm.prg
dlinboxt.prg
dlinboxb.prg
linprm23.prg
linmsg23.prg
prtmsg23.prg
getfld23.prg
prevmo.prg
nextmo.prg
passwerd.prg
lincount.prg
* displrut.prg
DISPLRUT.PRG is an educational text file, not a dbaseIII
executable PRG file per se. It is invaluable as a routine
to write to EITHER print or to screen, and is easily custom-
izable.
Again, these files are identical to the prg's described above
but they are collected into one file for archival purposes.
DB3STOCK.SKL -- An ascii text file, which contains the following procedures:
procedure bigboxdt
procedure boxclear
procedure smallbox
procedure lineboxm
procedure slinboxm
procedure slinboxt
procedure slinboxb
procedure dlinboxm
procedure dlinboxt
procedure dlinboxb
procedure linprm23
procedure linmsg23
procedure prtmsg23
procedure getfld23
procedure prevmo
procedure nextmo
procedure passwerd
These files are IDENTICAL to the PRG's as listed above, but
they have been put into a procedure file. You can then do
one of two things with this file:
1). Merge it directly at the end of any of your current
dbaseIII procedure file and you can now make any calls
to the above subroutines directly.
2). Do you use the new GENIFER (TM) program from Bytel Corporation?
(It is an OUTSTANDING APPLICATIONS GENERATOR -- the best I
have EVER seen. It is worth every penny of the $295.00 I
paid for it. I spent about six hours giving GENIFER the
parameters for the code I needed generated. GENIFER took
about 30 minutes generating the code. I then charged the
client 800 bucks. The client loved it, and so did I.)
Using a simple text editor, I have merged DB3STOCK.SKL to
the very end of the three GENIFER ".SKL" files that come
with GENIFER. The last line of every GENIFER ".SKL" file
contains the line,
"wd* EOF {{program}}"
where GENIFER replaces "{{program}}" with your program
name when the program is generated. JUST ABOVE THIS LINE
use the MERGE function (or block insert or block merge
or file merge or whatever your word processor/editor
calls it) of "DB3STOCK.SKL" INTO each of these GENIFER
".SKL" files. Every program now generated with GENIFER
will now also generate these subroutines for your program
AUTOMATICALLY.
Hope these routines are of some benefit. Give me some feedback on how you
might find ways to improve on them!
Scott Brock
The Outer Bridge
1600 San Fernando Blvd. Suite 235
Burbank, CA. 91504
1-818-848-8955